package parser;

import java.util.List;

import parser.table.LALRTableBuilder;
import parser.table.TableBuilder;
import scanner.Scanner;
import scanner.ScannerInterface;
import scanner.ScannerOutput;
import structures.grammar.Grammar;
import structures.grammar.GrammarReader;
import structures.parserStructures.ParseError;
import structures.parserStructures.ParserOutput;
import structures.table.LRTable;
import structures.table.symboltable.ItemInfo;

public class ParseController {
	private List<ItemInfo> items;
	private Grammar grammar;
	private GrammarReader reader;
	private ScannerInterface scanner;
	private ScannerOutput scannerOut;
	private ParserInterface parser;
	private TableBuilder builder;
	private Class<?> builderClass;
	private String sourceCode;
	private String grammarCode;

	public ParseController() {
	}

	public void setReader(GrammarReader reader) {
		this.reader = reader;
	}

	public void setScanner(Scanner scanner) {
		this.scanner = scanner;
	}

	public void setBuilder(Class<?> builder) {
		this.builderClass = builder;
	}

	public void setSourceCode(String sourceCode) {
		this.sourceCode = sourceCode;
	}

	public void setGrammar(String grammarCode) {
		this.grammarCode = grammarCode;
	}
	
	private boolean isReady() {
		return !(reader == null || scanner == null);
	}

	private boolean prepareParse() {
		grammar = reader.parse(grammarCode);
		scannerOut = scanner.scan(sourceCode);

		if (!scannerOut.getError().hasErrors()) {
			items = scannerOut.getItems();
			return true;
		} else {
			return false;
		}
	}

	public ScannerOutput getScannerOut() {
		return scannerOut;
	}
	
	private void makeBuilder() {
		if (builderClass.equals(TableBuilder.class)) {
			builder = new TableBuilder(grammar);
		} else if (builderClass.equals(LALRTableBuilder.class)) {
			builder = new LALRTableBuilder(grammar);
		}
	}

	public ParserOutput parse() {
		if (isReady() && prepareParse()) {
			makeBuilder();
			builder.build();

			parser = new Parser(builder.getActions(), builder.getGotos());

			return parser.parse(items);
		} else {
			return new ParserOutput(ParseError.ERROR);
		}
	}

	public LRTable getActions() {
		return builder.getActions();
	}

	public LRTable getGotos() {
		return builder.getGotos();
	}
}
